﻿using System.Data;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Devonline.Core;
using Devonline.Http;
using Devonline.Identity.Admin.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Devonline.Identity.Admin.Controllers
{
    /// <summary>
    /// 用户管理
    /// </summary>    
    [Route("api/[controller]")]
    [SecurityHeaders]
    [ApiController]
    [Authorize(Roles = AppSettings.GROUP_MAINTAINERS)]
    public class UsersController : ControllerBase
    {
        private readonly AdminSetting _appSetting;
        private readonly IdentityDbContext _context;
        private readonly UserManager<User> _userManager;
        private readonly RoleManager<Role> _roleManager;
        private readonly UserStore _userStore;
        private readonly ILogger<UsersController> _logger;
        private readonly IDataProtectionProvider _protector;
        private static CancellationToken CancellationToken => CancellationToken.None;

        public UsersController(
            AdminSetting appSetting,
            IdentityDbContext context,
            UserManager<User> userManager,
            RoleManager<Role> roleManager,
            UserStore userStore,
            IDataProtectionProvider provider,
            ILogger<UsersController> logger)
        {
            _appSetting = appSetting;
            _context = context;
            _userManager = userManager;
            _roleManager = roleManager;
            _userStore = userStore;
            _logger = logger;
            _userManager.Logger = _logger;
            _protector = provider;
        }

        #region 基础操作
        /// <summary>
        /// get user for claim
        /// </summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        [HttpGet]
        [EnableQuery]
        public IActionResult Get()
        {
            _logger.LogInformation("user {user} query the user list", User.Identity.Name);
            return Ok(_context.Users);
        }
        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> CreateAsync(CreateUserViewModel viewModel)
        {
            _logger.LogInformation("user {user} will add the user {targetUser}", User.Identity.Name, viewModel);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user != null)
            {
                return BadRequest($"用户名 {viewModel.UserName} 已经存在!");
            }

            user = new User
            {
                Name = viewModel.Name,
                UserName = viewModel.UserName,
                Email = viewModel.Email,
                PhoneNumber = viewModel.PhoneNumber,
                Alias = viewModel.Alias,
                Image = viewModel.Image,
                AuthType = AuthType.Password,
                Type = IdentityType.Internal,
                Description = viewModel.Description
            };

            user.Create(User.Identity.Name);
            user.Update(User.Identity.Name);
            var result = await _userManager.CreateAsync(user);
            if (result.Succeeded)
            {
                result = await _userManager.AddPasswordAsync(user, _appSetting.DefaultPassword);
                if (result.Succeeded)
                {
                    _logger.LogWarning("user {user} success to add the user {targetUser} for default password", User.Identity.Name, viewModel.UserName);
                }
                else
                {
                    _logger.LogWarning("user {user} success to add the user {targetUser} but no password", User.Identity.Name, viewModel.UserName);
                }

                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to add the user {targetUser}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 新增用户的一个 Claim
        /// </summary>
        /// <param name="id"></param>
        /// <param name="claim"></param>
        /// <returns></returns>
        [HttpPut("AddClaim/{id}")]
        public async Task<ActionResult> AddClaimAsync(string id, Claim claim)
        {
            _logger.LogInformation("user {user} will add claim to user {targetUser}", User.Identity.Name, id);
            var user = await _userManager.FindByIdAsync(id);
            if (user == null)
            {
                return BadRequest($"用户 {id} 不存在!");
            }

            var result = await _userManager.AddClaimAsync(user, claim);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to add claim to user {targetUser}", User.Identity.Name, user.Name);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to add claim to user {targetUser}, error message is: {errorMessage}", User.Identity.Name, user.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 移除用户的一个 Claim
        /// </summary>
        /// <param name="id"></param>
        /// <param name="claim"></param>
        /// <returns></returns>
        [HttpPut("RemoveClaim/{id}")]
        public async Task<ActionResult> RemoveClaimAsync(string id, Claim claim)
        {
            _logger.LogInformation("user {user} will remove claim to user {targetUser}", User.Identity.Name, id);
            var user = await _userManager.FindByIdAsync(id);
            if (user == null)
            {
                return BadRequest($"用户 {id} 不存在!");
            }

            var result = await _userManager.RemoveClaimAsync(user, claim);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to remove claim to user {targetUser}", User.Identity.Name, user.Name);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to remove claim to user {targetUser}, error message is: {errorMessage}", User.Identity.Name, user.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 删除用户(逻辑删除)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        [Authorize(Roles = AppSettings.GROUP_MAINTAINERS)]
        public async Task<IActionResult> DeleteAsync(string id)
        {
            _logger.LogInformation("user {user} will logic delete the user {targetUser}", User.Identity.Name, id);
            var user = await _userManager.FindByIdAsync(id);
            if (user == null)
            {
                return BadRequest($"用户 {id} 不存在!");
            }

            user.State = DataState.Deleted;
            var result = await _userManager.UpdateAsync(user);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to logic delete the user {targetUser}", User.Identity.Name, user.UserName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to logic delete the user {targetUser}, error message is: {errorMessage}", User.Identity.Name, user.UserName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        #endregion

        #region 用户敏感信息
        /// <summary>
        /// 设置用户级别
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("SetLevel")]
        public async Task<IActionResult> SetLevelAsync(UserLevelViewModel viewModel)
        {
            _logger.LogInformation("user {user} will set user {targetUser} level to {level}", User.Identity.Name, viewModel.UserName, viewModel.LevelName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            await _userStore.SetLevel(user, viewModel.LevelName, CancellationToken);
            user.Update(User.Identity.Name);
            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                return Ok();
            }

            return BadRequest();
        }

        [HttpPost("ChangePassword")]
        public async Task<IActionResult> ChangePasswordAsync(ChangePasswordViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the password for user {targetUser}", User.Identity.Name, viewModel.UserName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userManager.ChangePasswordAsync(user, viewModel.Password, viewModel.NewPassword);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to change the password for user {targetUser}", User.Identity.Name, viewModel.UserName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to change the password for user {targetUser}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        [HttpPost("ResetPassword")]
        [Authorize(Roles = AppSettings.GROUP_MAINTAINERS)]
        public async Task<IActionResult> ResetPasswordAsync(ResetPasswordViewModel viewModel)
        {
            _logger.LogInformation("user {user} will reset the password user {targetUser}", User.Identity.Name, viewModel.UserName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userManager.ResetPasswordAsync(user, viewModel.Token, viewModel.Password);

            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to reset the password for user {targetUser}", User.Identity.Name, viewModel.UserName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to reset the password for user {targetUser}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        [HttpPost("ChangePhoneNumber")]
        public async Task<IActionResult> ChangePhoneNumberAsync(ChangePhoneNumberViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the phone number for user {targetUser}", User.Identity.Name, viewModel.UserName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userManager.ChangePhoneNumberAsync(user, viewModel.PhoneNumber, viewModel.Token);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to change the phone number for user {targetUser}", User.Identity.Name, viewModel.UserName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to change the phone number for user {targetUser}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        [HttpPost("ChangeEmail")]
        public async Task<IActionResult> ChangeEmailAsync(ChangeEmailViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the email for user {targetUser}", User.Identity.Name, viewModel.UserName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userManager.ChangeEmailAsync(user, viewModel.Email, viewModel.Token);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to change the email for user {targetUser}", User.Identity.Name, viewModel.UserName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to change the email for user {targetUser}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        #endregion

        #region 用户角色
        /// <summary>
        /// 获取用户角色列表
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        [HttpGet("GetUserRoles/{userName}")]
        public async Task<ActionResult> GetUserRolesAsync(string userName)
        {
            _logger.LogInformation("user {user} will query user {targetUser} roles", User.Identity.Name, userName);
            var user = await _userManager.FindByNameAsync(userName);
            if (user == null)
            {
                return BadRequest($"用户 {userName} 不存在!");
            }

            return Ok(await _userManager.GetRolesAsync(user));
        }
        /// <summary>
        /// 获取某个角色的用户列表
        /// </summary>
        /// <param name="roleName"></param>
        /// <returns></returns>
        [HttpGet("GetRoleUsers/{roleName}")]
        public async Task<IActionResult> GetRoleUsersAsync(string roleName)
        {
            _logger.LogInformation("user {user} will query role {role} users", User.Identity.Name, roleName);
            if (!await _roleManager.RoleExistsAsync(roleName))
            {
                return BadRequest($"角色 {roleName} 不存在!");
            }

            return Ok(await _userManager.GetUsersInRoleAsync(roleName));
        }
        /// <summary>
        /// 将用户添加到角色
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="role"></param>
        /// <returns></returns>
        [HttpPost("AddUserToRole")]
        public async Task<IActionResult> AddUserToRoleAsync(UserRoleViewModel viewModel)
        {
            _logger.LogInformation("user {user} will assign user {targetUser} to role {role}", User.Identity.Name, viewModel.UserName, viewModel.RoleName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userManager.AddToRoleAsync(user, viewModel.RoleName);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success assign user {targetUser} to role {role}", User.Identity.Name, viewModel.UserName, viewModel.RoleName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail assign user {targetUser} to role {role}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, viewModel.RoleName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 从角色中移除用户(物理删除)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost("RemoveUserFromRole")]
        public async Task<IActionResult> RemoveUserFromRoleAsync(UserRoleViewModel viewModel)
        {
            _logger.LogInformation("user {user} will remove user {targetUser} from role {role}", User.Identity.Name, viewModel.UserName, viewModel.RoleName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userManager.RemoveFromRoleAsync(user, viewModel.RoleName);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success remove user {targetUser} from role {role}", User.Identity.Name, viewModel.UserName, viewModel.RoleName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail remove user {targetUser} from role {role}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, viewModel.RoleName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        #endregion

        #region 用户组
        /// <summary>
        /// 获取用户所在组列表, 返回组名称字符串数组
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        [HttpGet("GetUserGroups/{userName}")]
        public async Task<ActionResult> GetUserGroupsAsync(string userName)
        {
            _logger.LogInformation("user {user} will query user {targetUser} groups", User.Identity.Name, userName);
            var user = await _userManager.FindByNameAsync(userName);
            if (user == null)
            {
                return BadRequest($"用户 {userName} 不存在!");
            }

            return Ok(await _userStore.GetUserGroupsAsync(user, CancellationToken));
        }
        /// <summary>
        /// 获取组用户列表, 返回用户列表
        /// TODO TBC 目前没有分页, 此处需要返回分页结果
        /// </summary>
        /// <param name="groupName"></param>
        /// <returns></returns>
        [HttpGet("GetGroupUsers/{groupName}")]
        public async Task<IActionResult> GetGroupUsersAsync(string groupName)
        {
            _logger.LogInformation("user {user} will query group {group} users", User.Identity.Name, groupName);
            if (!await _roleManager.RoleExistsAsync(groupName))
            {
                return BadRequest($"用户组 {groupName} 不存在!");
            }

            var users = await _userStore.GetGroupUsersAsync(groupName, CancellationToken);
            if (users.IsNotNullOrEmpty())
            {
                var result = users.Select(x => new UserListModel
                {
                    Id = x.Id,
                    UserName = x.UserName,
                    Alias = x.Alias,
                    Description = x.Description,
                    Email = x.Email,
                    Image = x.Image,
                    Name = x.Name,
                    PhoneNumber = x.PhoneNumber,
                    State = x.State
                }).ToList();

                return Ok(new PagedResult<UserListModel> { Rows = result });
            }

            return Ok();
        }
        /// <summary>
        /// 将用户添加到组
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("AddUserToGroup")]
        public async Task<IActionResult> AddUserToGroupAsync(UserGroupViewModel viewModel)
        {
            _logger.LogInformation("user {user} will assign user {targetUser} to group {group}", User.Identity.Name, viewModel.UserName, viewModel.GroupName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userStore.AddToGroupAsync(user, viewModel.GroupName, CancellationToken);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success assign user {targetUser} to group {group}", User.Identity.Name, viewModel.UserName, viewModel.GroupName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail assign user {targetUser} to group {group}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, viewModel.GroupName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 从组中移除用户(物理删除)
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("RemoveUserFromGroup")]
        public async Task<IActionResult> RemoveUserFromGroupAsync(UserGroupViewModel viewModel)
        {
            _logger.LogInformation("user {user} will remove user {targetUser} from group {group}", User.Identity.Name, viewModel.UserName, viewModel.GroupName);
            var user = await _userManager.FindByNameAsync(viewModel.UserName);
            if (user == null)
            {
                return BadRequest($"用户 {viewModel.UserName} 不存在!");
            }

            var result = await _userStore.RemoveFromGroupAsync(user, viewModel.GroupName, CancellationToken);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success remove user {targetUser} from group {group}", User.Identity.Name, viewModel.UserName, viewModel.GroupName);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail remove user {targetUser} from group {group}, error message is: {errorMessage}", User.Identity.Name, viewModel.UserName, viewModel.GroupName, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        #endregion
    }
}
